package com.lib76.socket.message;

import java.io.EOFException;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.List;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;

import com.lib76.socket.model.SocketMessage;
import com.lib76.socket.model.protocol.SocketProtocolGroup;
import com.lib76.socket.model.protocol.SocketProtocolObject;
import com.lib76.socket.model.protocol.SocketProtocolParameter;

public class ByteSocketMessage extends SocketMessage{
	
	private ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
	
	public ByteSocketMessage() {
		super();
	}

	public ByteSocketMessage(Object originalMessage) {
		super(originalMessage);
	}

	public ByteSocketMessage(SocketProtocolObject protocolObject,
			Object originalMessage) {
		super(protocolObject, originalMessage);
	}

	public ByteSocketMessage(SocketProtocolObject protocolObject) {
		super(protocolObject);
	}

	@Override
	public void read(List<SocketProtocolParameter> parameters) throws Exception {
		for(int i=0;i<parameters.size();i++){
    		SocketProtocolParameter param = parameters.get(i);
    		if(SocketProtocolParameter.PARAMETER_TYPE_STRING.equals(param.getType())){
    			this.data.put(param.getName(), this.readString(param.getLength()));
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_INTEGER.equals(param.getType())){
    			if(param.getLength() == 1){
    				this.data.put(param.getName(), buffer.readUnsignedByte());
    			}else if(param.getLength() == 2){
    				this.data.put(param.getName(), buffer.readChar());
    			}else{
    				this.data.put(param.getName(), buffer.readInt());
    			}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_LONG.equals(param.getType())){
    			if(param.getLength() == 4){
    				this.data.put(param.getName(), (long)buffer.readInt());
    			}else{
    				this.data.put(param.getName(), buffer.readLong());
    			}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_DOUBLE.equals(param.getType())){
    			if(param.getLength() == 4){
    				this.data.put(param.getName(), (double)buffer.readInt());
    			}else{
    				this.data.put(param.getName(), buffer.readDouble());
    			}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_FLOAT.equals(param.getType())){
    			if(param.getLength() == 2){
    				this.data.put(param.getName(), buffer.readChar());
    			}else{
    				this.data.put(param.getName(),buffer.readFloat());
    			}
    		}
    	}
	}
	
	@Override
	public void write(List<SocketProtocolParameter> parameters)
			throws Exception {
		for(SocketProtocolParameter param : parameters){
			Object obj = this.data.get(param.getName());
			if(obj == null){
				if(SocketProtocolGroup.COMMAND_FIELD_NAME.equals(param.getName())){
					obj = this.protocolObject.getCommand();
				}else if(SocketProtocolGroup.BODY_TYPE_FIELD_NAME.equals(param.getName())){
					obj = this.protocolObject.getBodyType();
				}else if(SocketProtocolGroup.BODY_LENGTH_FIELD_NAME.equals(param.getName())){
					obj = this.protocolObject.getBodyLength();
				}else if(SocketProtocolGroup.DIRECTION_FIELD_NAME.equals(param.getName())){
					obj = this.protocolObject.getDirection();
				}else{
					obj = param.getValue();
				}
			}
			if(SocketProtocolParameter.PARAMETER_TYPE_STRING.equals(param.getType())){
				if(obj != null){
					this.writeString(obj.toString(), param.getLength());
				}else{
					byte[] buff = (byte[])Array.newInstance(byte.class,param.getLength());
					buffer.writeBytes(buff);
				}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_INTEGER.equals(param.getType())){
    			if(obj != null){
	    			if(param.getLength() == 1){
	    				buffer.writeByte(Integer.valueOf(obj.toString()));
	    			}else if(param.getLength() == 2){
	    				buffer.writeChar(Integer.valueOf(obj.toString()));
	    			}else{
	    				buffer.writeInt(Integer.valueOf(obj.toString()));
	    			}
    			}else{
    				byte[] buff = (byte[])Array.newInstance(byte.class,param.getLength());
					buffer.writeBytes(buff);
    			}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_LONG.equals(param.getType())){
    			if(obj != null){
	    			if(param.getLength() == 4){
	    				buffer.writeInt(Integer.valueOf(obj.toString()));
	    			}else{
	    				buffer.writeLong(Long.valueOf(obj.toString()));
	    			}
    			}else{
    				byte[] buff = (byte[])Array.newInstance(byte.class,param.getLength());
					buffer.writeBytes(buff);
    			}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_DOUBLE.equals(param.getType())){
    			if(obj != null){
	    			if(param.getLength() == 4){
	    				buffer.writeInt(Integer.valueOf(obj.toString()));
	    			}else{
	    				buffer.writeDouble(Double.valueOf(obj.toString()));
	    			}
    			}else{
    				byte[] buff = (byte[])Array.newInstance(byte.class,param.getLength());
					buffer.writeBytes(buff);
    			}
    		}else if(SocketProtocolParameter.PARAMETER_TYPE_FLOAT.equals(param.getType())){
    			if(obj != null){
    				if(param.getLength() == 2){
	    				buffer.writeChar(Integer.valueOf(obj.toString()));
	    			}else{
	    				buffer.writeFloat(Float.valueOf(obj.toString()));
	    			}
    			}else{
    				byte[] buff = (byte[])Array.newInstance(byte.class,param.getLength());
					buffer.writeBytes(buff);
    			}
    		}else{
    			throw new EOFException();
    		}
		}
	}

	@Override
	public Object buildMessage() throws Exception {
		if(this.isOriginalMessageOutput == false && this.hasProtocol()){
			write(protocolObject.getHeaderProtocolParameter());
			write(protocolObject.getBodyFields());
			return buffer;
		}else if(originalMessage != null){
			if(!ChannelBuffer.class.isInstance(originalMessage)){
				if(String.class.isInstance(originalMessage)){
					buffer.writeBytes(originalMessage.toString().getBytes());
				}else if(originalMessage.getClass().isArray()){
					buffer.writeBytes((byte[])originalMessage);
				}
				return buffer;
			}else{
				return originalMessage;
			}
		}
		return null;
	}
	
	public String readString(int size){
        byte[] buff = (byte[])Array.newInstance(byte.class,size);
		buffer.readBytes(buff);
        return new String(buff);
	}

	public void writeString(String content, int size) throws IOException {
		buffer.writeBytes(content.getBytes(),0,size);
	}

	@Override
	public void readOriginalMessage(Object originalMessage){
		if(!ChannelBuffer.class.isInstance(originalMessage)){
			if(String.class.isInstance(originalMessage)){
				buffer = ChannelBuffers.dynamicBuffer();
				buffer.writeBytes(originalMessage.toString().getBytes());
			}else if(originalMessage.getClass().isArray()){
				buffer = ChannelBuffers.dynamicBuffer();
				buffer.writeBytes((byte[])originalMessage);
			}
		}else{
			buffer = (ChannelBuffer)originalMessage;
		}
	}
	
}
